// src/utils/GIS.js
import { Map, View } from 'ol'
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import LayerGroup from 'ol/layer/Group.js'
import XYZ from 'ol/source/XYZ'
import VectorSource from 'ol/source/Vector'
import GeoJSON from 'ol/format/GeoJSON'
import { fromLonLat } from 'ol/proj'
import { Style, Stroke, Fill, Text, Icon } from 'ol/style'
import Draw from 'ol/interaction/Draw'
import { Circle as CircleStyle } from 'ol/style'
import 'ol/ol.css' // 引入 OpenLayers 的样式
import { Feature } from 'ol'
import { Point } from 'ol/geom'
import WKT from 'ol/format/WKT'

/**
 * GIS类 - 封装了OpenLayers地图操作的核心功能
 * 提供地图初始化、图层管理、绘制工具、空间分析等功能
 *
 * 图层类型说明：
 *   base: 基础图层（如底图）
 *   important: 重要图层（如重点要素）
 *   relate: 相关图层（如辅助要素）
 */
export class GIS {
  /**
   * 构造函数
   * @param {Object} options - 配置选项
   * @param {string} options.apiKey - 天地图API密钥
   * @param {string} options.container - 地图容器DOM ID
   * @param {Array} options.center - 地图中心点坐标 [经度, 纬度]
   * @param {number} options.zoom - 初始缩放级别
   */
  constructor(options = {}) {
    this.apiKey = options.apiKey || '' // 天地图 API 密钥
    this.container = options.container || null // 地图容器 DOM
    this.center = options.center || [107.2306393, 34.3645] // 默认宝鸡
    this.zoom = options.zoom || 9 // 默认缩放级别
    this.projection = 'EPSG:4326' // 地图投影
    this.map = null // 地图实例
    this.geojsonLayer = null // GeoJSON图层
    this.drawLayer = null // 绘制图层
    this.drawInteraction = null // 绘制交互
    this.drawSource = null // 绘制数据源
    this.featuresLayer = null // 图斑数据图层
    this.selectInteraction = null // 选择交互
    this.layers = [] // 图层列表
    this.swipe = 0.5 // 卷帘位置
    this.swipeLayer = null // 卷帘图层
    this.swipePosition = 0.5 // 卷帘位置
  }

  // 图层名称枚举
  layerNameEmun = {
    FEATURE: '图斑数据',
    DRAW: '绘制图层',
    TDTIMAGE: '天地图影像',
    TDTVECTOR: '天地图注记',
  }

  // 图层类型映射
  layerTypeMap = {
    vector: ['vec', 'cva'], // [矢量底图, 矢量注记]
    image: ['img', 'cva'], // [影像底图, 影像注记]
    vimage: ['img', 'cva'], // [影像底图, 影像注记]
    terrain: ['ter', 'cta'], // [地形晕渲, 地形注记]
  }

  /**
   * 计算指定缩放级别的分辨率
   * @param {number} zoom - 缩放级别
   * @returns {number} 分辨率
   */
  getResolutionForZoom(zoom) {
    return 180 / (256 * Math.pow(2, zoom)) // EPSG:4326 近似分辨率
  }

  /**
   * 添加矢量图层
   * @param {string} name - 图层名称
   * @param {string} type - 图层类型
   * @returns {VectorLayer} 创建的矢量图层
   */
  addVectorLayer(name, type) {
    let layer = new VectorLayer({
      source: new VectorSource(),
      properties: {
        name: name,
        type: type,
      },
    })
    this.layers.push(layer)
    this.map.addLayer(layer)
    return layer
  }

  /**
   * 清除图层内容
   * @param {VectorLayer} layer - 要清除的图层
   */
  clearLayer(layer) {
    layer.getSource().clear()
  }

  /**
   * 初始化地图
   * @param {string} layerType - 底图类型（vector/image/terrain）
   * @returns {GIS} 返回this以支持链式调用
   */
  initMap(layerType = 'image') {
    if (!this.container) {
      throw new Error('缺少地图容器')
    }
    const matrixSet = 'w'
    this.map = new Map({
      target: this.container,
      layers: [
        // 底图
        new TileLayer({
          source: new XYZ({
            // url: `http://t0.tianditu.gov.cn/${this.layerTypeMap[layerType][0]}_${matrixSet}/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&TILEMATRIXSET=w&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${this.apiKey}`,

            url: `http://t{0-7}.tianditu.com/DataServer?T=${this.layerTypeMap[layerType][0]}_${matrixSet}&x={x}&y={y}&l={z}&tk=${this.apiKey}`,
            layer: this.layerTypeMap[layerType][0],
            matrixSet: matrixSet,
            style: 'default',
            crossOrigin: 'anonymous',
            format: 'tiles',
            wrapX: true,
          }),
          properties: {
            name: this.layerNameEmun.TDTIMAGE,
            type: 'base',
          },
        }),
        // 注记
        new TileLayer({
          source: new XYZ({
            url: `http://t{0-7}.tianditu.gov.cn/${this.layerTypeMap[layerType][1]}_${matrixSet}/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${this.apiKey}`,
            layer: this.layerTypeMap[layerType][1],
            matrixSet: matrixSet,
            style: 'default',
            crossOrigin: 'anonymous',
            format: 'tiles',
            wrapX: true,
          }),
          properties: {
            name: this.layerNameEmun.TDTVECTOR,
            type: 'base',
          },
        }),
      ],
      view: new View({
        center: this.center,
        zoom: this.zoom,
        projection: this.projection,
        maxZoom: 17,
        minZoom: 9,
      }),
    })

    return this
  }

  /**
   * 注册地图点击事件
   * @param {Function} callback - 点击回调函数，接收要素属性作为参数
   */
  registerMapClick(callback) {
    if (!this.map) {
      return
    }
    // 添加点击事件监听
    this.map.on('click', (event) => {
      this.map.forEachFeatureAtPixel(event.pixel, (feature, layer) => {
        let layername = layer.get('name')
        if (layername == this.layerNameEmun.FEATURE) {
          let attr = feature.getProperties()
          if (attr) {
            callback(feature.getProperties())
          }
        }
      })
    })
  }

  /**
   * 刷新地图
   * @param {number} swipe - 卷帘位置
   */
  refresh(swipe) {
    console.log(this.swipe)
    this.swipe = swipe
    this.map.render()
  }

  /**
   * 清除图层事件
   * @param {Layer} layer - 要清除事件的图层
   */
  clearEvent(layer) {
    layer.on('prerender', function () {
      console.log('清空事件')
    })
    layer.on('postrender', function () {
      console.log('清空事件')
    })
    this.swipeLayer = null
    this.swipePosition = 1
  }

  /**
   * 初始化卷帘图层
   * @param {Layer} layer - 要添加卷帘效果的图层
   */
  initswipelayer(layer) {
    if (!layer) return

    // 清除之前的卷帘效果
    if (this.swipeLayer) {
      this.clearEvent(this.swipeLayer)
    }

    this.swipeLayer = layer

    // 添加卷帘效果
    layer.on('prerender', (event) => {
      const ctx = event.context
      const width = ctx.canvas.width * this.swipePosition

      ctx.save()
      ctx.beginPath()
      ctx.rect(0, 0, width, ctx.canvas.height)
      ctx.clip()
    })

    layer.on('postrender', (event) => {
      event.context.restore()
    })
  }

  /**
   * 更新卷帘位置
   * @param {number} position - 卷帘位置（0-1之间）
   */
  updateSwipePosition(position) {
    this.swipePosition = position
    if (this.swipeLayer) {
      this.swipeLayer.changed()
    }
  }

  /**
   * 创建多边形样式
   * @param {Object} style - 样式配置
   * @param {number} zoom - 当前缩放级别
   * @returns {Style} OpenLayers样式对象
   */
  createPolygonStyle(style, zoom = 10) {
    let feature_style
    switch (style.type) {
      case 'icon':
        let baseScale = style.baseScale || 1
        let scale = baseScale * Math.pow(1.15, zoom - 10)
        feature_style = new Style({
          image: new Icon({
            anchor: [0.5, 1],
            scale: scale * 1,
            src: style.img,
          }),
        })
        break
      case 'polygon':
        feature_style = new Style({
          fill: new Fill({
            color: style.fillcolor || 'rgba(0, 255, 0, 0.3)',
          }),
          stroke: new Stroke({
            color: style.strokeColor || 'rgba(0, 255, 0, 0.3)',
            width: style.strokeWidth || 1,
          }),
          declutter: true,
        })
        break
      case 'line':
        feature_style = new Style({
          stroke: new Stroke({
            color: style.strokeColor || 'rgba(0, 255, 0, 0.3)',
            width: style.strokeWidth || 1,
          }),
        })
        break
    }
    if (style.text) {
      let text = new Text({
        text: style.text,
        font: '14px sans-serif',
        fill: new Fill({ color:  '#ffffff' }),
        stroke: new Stroke({
          color: '#000000', // 描边颜色（白色）
          width: 1 // 描边宽度
        }),


        // 但如果你想在样式函数中明确指定几何体，可以使用：
        // geometry: feature.getGeometry().getInteriorPoint(),
        overflow: false, // 允许注记超出多边形边界，有助于 decluttering
        placement: 'point', // 即使是多边形，注记依然是点状放置
        // align 和 baseline 配合，可以将文本精确对齐到内部点
        textAlign: 'center',
        textBaseline: 'middle',
      })
      feature_style.setText(text)
    }
    return feature_style
  }

  /**
   * 加载GeoJSON数据
   * @param {string} url - GeoJSON文件URL
   * @param {Object} options - 配置选项
   * @param {string} options.layerName - 图层名称
   * @param {string} options.layerType - 图层类型
   * @param {string} options.textfiled - 文本字段
   * @param {Object} options.style - 样式配置
   */
  async loadGeoJSON(url, options) {
    const response = await fetch(url)
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }
    const geojsonData = await response.json()
    const geojsonFormat = new GeoJSON()

    const source = new VectorSource({
      features: geojsonFormat.readFeatures(geojsonData),
      projection: this.projection,
    })
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const self = this

    let layer = new VectorLayer({
      source,
      properties: {
        name: options.layerName,
        type: options.layerType,
      },
      maxZoom: options.maxZoom || 17,
      minZoom:options.minZoom|| 5,
      style: (feature, resolution) => {
        let style = options.style
        if (options.textfiled) {
          style.text = feature.get(options.textfiled) || ''
        }
        let zoom = this.map.getView().getZoomForResolution(resolution)
        return self.createPolygonStyle(style, zoom)
      },
    })
    this.map.addLayer(layer)
  }

  /**
   * 获取所有图层
   * @returns {Array} 图层数组
   */
  getlayertype() {
    const layers = []

    // 递归函数，处理图层和图层组
    function collectLayers(layer) {
      if (layer instanceof LayerGroup) {
        // 如果是图层组，递归获取其子图层
        layer.getLayers().forEach(collectLayers)
      } else {
        // 如果是普通图层，添加到结果数组
        layers.push(layer)
      }
    }

    // 获取地图的所有顶层图层/图层组
    this.map.getLayers().forEach(collectLayers)
    console.log(layers)
   let sublayer= layers.filter(d=>d.get('type')!=='base')

    return sublayer
  }

  /**
   * 缩放到指定图层
   * @param {Layer} layer - 目标图层
   */
  zoomToLayer(layer) {
    console.log(layer, this.map)
  }

  /**
   * 缩放到WKT几何范围
   * @param {string} wkt - WKT格式的几何数据
   */
  zoomToWkt(wkt) {
    const format = new WKT()
    const feature = format.readFeature(wkt, {
      dataProjection: 'EPSG:4326',
      featureProjection: 'EPSG:4326',
    })
    console.log(222, feature.getGeometry().getExtent())
    this.map.getView().fit(feature.getGeometry().getExtent(), {
      padding: [50, 50, 50, 50],
      duration: 1000,
    })
  }

  /**
   * 设置地图中心点
   * @param {Array} lonLat - 经纬度坐标 [经度, 纬度]
   * @param {number} zoom - 缩放级别
   */
  setCenter(lonLat, zoom) {
    this.map.getView().setCenter(fromLonLat(lonLat, this.projection))
    if (zoom !== undefined) {
      this.map.getView().setZoom(zoom)
    }
  }

  /**
   * 设置缩放级别
   * @param {number} zoom - 缩放级别
   */
  setZoom(zoom) {
    this.map.getView().setZoom(zoom)
  }

  /**
   * 获取当前缩放级别
   * @returns {number} 当前缩放级别
   */
  getZoom() {
    return this.map.getView().getZoom()
  }

  /**
   * 清除GeoJSON图层
   */
  clearGeoJSON() {
    if (this.geojsonLayer) {
      this.map.removeLayer(this.geojsonLayer)
      this.geojsonLayer = null
    }
  }

  /**
   * 初始化绘制图层
   */
  initDrawLayer() {
    if (!this.drawLayer) {
      this.drawSource = new VectorSource()
      this.drawLayer = new VectorLayer({
        source: this.drawSource,
        style: new Style({
          fill: new Fill({
            color: 'rgba(255, 255, 255, 0.2)',
          }),
          stroke: new Stroke({
            color: '#ffcc33',
            width: 2,
          }),
          image: new CircleStyle({
            radius: 7,
            fill: new Fill({
              color: '#ffcc33',
            }),
          }),
        }),
      })
      this.drawLayer.set('name', this.layerNameEmun.DRAW)
      this.drawLayer.set('type', 'temp')
      this.map.addLayer(this.drawLayer)
    }
  }

  /**
   * 开启绘制功能
   * @param {string} type - 绘制类型（Point/LineString/Polygon/Circle）
   * @param {Function} callback - 绘制完成回调函数
   */
  startDraw(type, callback) {
    this.stopDraw()
    this.initDrawLayer()

    // 创建绘制交互
    this.drawInteraction = new Draw({
      source: this.drawSource,
      type: type,
    })

    // 添加绘制完成的事件监听
    this.drawInteraction.on('drawend', (event) => {
      const feature = event.feature
      console.log('绘制完成:', feature)
      // 创建 WKT 格式实例
      const wktFormat = new WKT()
      // 将 Feature 转换为 WKT 字符串
      const wktString = wktFormat.writeFeature(feature)
      callback(wktString)
    })

    this.map.addInteraction(this.drawInteraction)
  }

  /**
   * 停止绘制
   */
  stopDraw() {
    if (this.drawInteraction) {
      this.map.removeInteraction(this.drawInteraction)
      this.drawInteraction = null
    }
  }

  /**
   * 清除绘制的内容
   */
  clearDraw() {
    if (this.drawSource) {
      this.drawSource.clear()
    }
  }

  /**
   * 获取绘制的要素
   * @returns {Array} 绘制的要素数组
   */
  getDrawFeatures() {
    return this.drawSource ? this.drawSource.getFeatures() : []
  }

  /**
   * 销毁地图实例
   */
  destroy() {
    this.stopDraw()
    if (this.drawLayer) {
      this.map.removeLayer(this.drawLayer)
      this.drawLayer = null
    }
    if (this.map) {
      this.map.setTarget(null)
      this.map = null
    }
  }

  /**
   * 渲染缓冲区
   * @param {string} wkt - WKT格式的几何数据
   * @param {VectorLayer} layer - 目标图层
   * @param {Object} stylestr - 样式配置
   */
  renderBuffer(wkt, layer, stylestr) {
    try {
      if (!layer) {
        layer = this.drawLayer
      }
      if (!stylestr) {
        stylestr = {
          strokeColor: 'red',
          strokeWidth: 2,
          fillColor: 'rgba(255, 0, 0, 0.5)',
        }
      }
      if (!layer) {
        this.initDrawLayer()
      }

      const format = new WKT()
      const feature = format.readFeature(wkt, {
        dataProjection: 'EPSG:4326',
        featureProjection: 'EPSG:4326',
      })

      // 设置样式
      const style = new Style({
        stroke: new Stroke({
          color: stylestr.strokeColor,
          width: stylestr.strokeWidth,
        }),
        fill: new Fill({
          color: stylestr.fillColor,
        }),
      })

      feature.setStyle(style)
      layer.getSource().addFeature(feature)
    } catch (err) {
      console.log(err)
    }
  }

  /**
   * 渲染要素
   * @param {Array} features - 要素数据数组
   * @param {Function} callback - 点击要素回调函数
   */
  renderFeatures(features, callback) {
    if (!this.featuresLayer) {
      this.featuresLayer = new VectorLayer({
        source: new VectorSource(),
        style: (feature) => {
          const type = feature.get('ty')
          return this.getFeatureStyle(type)
        },
      })
      this.featuresLayer.set('name', this.layerNameEmun.FEATURE)
      this.featuresLayer.set('type', 'important')
      this.map.addLayer(this.featuresLayer)
    }

    // 移除旧的点击交互
    if (this.selectInteraction) {
      this.map.removeInteraction(this.selectInteraction)
    }

    const source = this.featuresLayer.getSource()
    source.clear()

    features.forEach((item) => {
      const feature = new Feature({
        geometry: new Point([item.x, item.y]),
        ...item,
      })

      source.addFeature(feature)
    })
    this.registerMapClick(callback)
  }

  /**
   * 获取要素样式
   * @param {string} type - 要素类型
   * @returns {Style} OpenLayers样式对象
   */
  getFeatureStyle(type) {
    const styles = {
      dj: new Style({
        image: new CircleStyle({
          radius: 8,
          fill: new Fill({ color: '#FF4B4B' }),
          stroke: new Stroke({ color: '#ffffff', width: 2 }),
        }),
      }),
      kf: new Style({
        image: new CircleStyle({
          radius: 8,
          fill: new Fill({ color: '#4B8BFF' }),
          stroke: new Stroke({ color: '#ffffff', width: 2 }),
        }),
      }),
      3: new Style({
        image: new CircleStyle({
          radius: 8,
          fill: new Fill({ color: '#44D7B6' }),
          stroke: new Stroke({ color: '#ffffff', width: 2 }),
        }),
      }),
    }
    return styles[type] || styles[1]
  }

  /**
   * 更新图层可见性
   * @param {Layer} layer - 目标图层
   */
  updateLayerVisibility(layer) {
    if (!layer) return

    // 获取所有图层
    const layers = this.getlayertype()

    // 先隐藏所有图层
    layers.forEach((l) => {
      if (l.get('type') !== 'base') {
        l.setVisible(false)
      }
    })

    // 显示选中的图层
    layer.setVisible(true)
  }

  /**
   * 将圆形转换为WKT格式
   * @param {Circle} circle - 圆形几何对象
   * @returns {string} WKT格式的几何数据
   */
  circleToWkt(circle) {
    if (!(circle instanceof CircleGeom)) {
      throw new Error('Geometry is not a Circle')
    }

    // 获取圆的中心和半径
    const center = circle.getCenter()
    const radius = circle.getRadius()
    const numPoints = 64 // 圆周上的点数，越多越接近圆形

    // 生成圆周上的点
    const points = []
    for (let i = 0; i < numPoints; i++) {
      const angle = (i / numPoints) * 2 * Math.PI
      const x = center[0] + radius * Math.cos(angle)
      const y = center[1] + radius * Math.sin(angle)
      points.push([x, y])
    }
    points.push(points[0]) // 闭合多边形

    // 创建多边形
    const polygon = new Polygon([points])

    // 使用 WKT 格式化器
    const wktFormat = new WKT()
    return wktFormat.writeGeometry(polygon)
  }
}
